/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦，本文采用木兰宽松许可证第2版]
 * 
 * https://zhiqim.org/project/zhiqim_kit/zhiqim_git.htm
 *
 * ZhiqimGit is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.git.objer.objectid;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.zhiqim.git.GitWalker;
import org.zhiqim.git.objer.model.PersonIdent;
import org.zhiqim.git.util.GitBytes;
import org.zhiqim.kernel.util.Bytes;
import org.zhiqim.kernel.util.DateTimes;
import org.zhiqim.kernel.util.Validates;
import org.zhiqim.kernel.util.mutables.MInt;

/**
 * 修改过程中的提交对象<br><br>
 * 
 * 格式如下：<br>
 * tree b11548de78dd3c90bc3bf7dba30c4062dc28a584<br>
 * parent ae2282f08a8a36c463d351d8b152868c2631b54d<br>
 * author 森中灵 <senyeah@qq.com> 1490791737 +0800<br>
 * committer 森中灵 <senyeah@qq.com> 1490791737 +0800<br><br>
 * 
 * 一二三四五<br>
 * 六七八九十<br>
 * 
 * @version v1.0.0 @author zhichenggang 2017-3-28 新建与整理
 */
public class RevCommit extends RevObject
{
    private RevTree tree;
    private List<RevCommit> parents;
    private PersonIdent author;
    private PersonIdent committer;
    private int commitTime;
    private byte[] buffer;

    public RevCommit(final ObjectId id)
    {
        super(id);
    }
    
    /***********************************************************************/
    //子类必须实现的5个方法
    /***********************************************************************/

    @Override
    public final int getType()
    {
        return OBJ_COMMIT;
    }
    
    @Override
    public void parseHeaders(GitWalker walk) throws IOException
    {
        parseCanonical(walk, loadCanonical(walk));
    }

    @Override
    public void parseBody(GitWalker walk) throws IOException
    {
        if (buffer == null)
        {
            buffer = loadCanonical(walk);
            if (!isParsed())
                parseCanonical(walk, buffer);
        }
    }
    
    @Override
    public final byte[] getContent()
    {
        return buffer;
    }
    
    @Override
    public final void disposeContent()
    {
        buffer = null;
    }
    
    /***********************************************************************/
    //解析内容
    /***********************************************************************/

    public void parseCanonical(GitWalker walk, byte[] content)
    {
        //1.一个tree ...
        tree = walk.lookupTree(ObjectId.parseHex(content, 5));

        //2.多个parent ...
        MInt off = new MInt(46);
        while (off.value < content.length && content[off.value] == 'p')
        {
            if (parents == null)
                parents = new ArrayList<>();
                
            RevCommit parent = walk.lookupCommit(ObjectId.parseHex(content, off.value + 7));
            parents.add(parent);
            off.value += 48;
        }

        //3.作者author ...
        if (off.value < content.length && content[off.value] == 'a')
        {
            off.skip(7);
            String str = Bytes.BU.getString(content, off, '\n');
            author = new PersonIdent(str);
        }
        
        //4.提交committer
        if (off.value < content.length && content[off.value] == 'c')
        {
            off.skip(10);
            String str = Bytes.BU.getString(content, off, '\n');
            committer = new PersonIdent(str);
            commitTime = committer.getCommitTime();
        }

        if (walk.isRetainBody())
        {//是否保留缓冲
            buffer = content;
        }
        
        setParsed();
    }
    
    /***********************************************************************/
    //递归设置标志
    /***********************************************************************/
    
    /** 递归Have标志到所有的父节点 */
    public void setHaveParentRecursion(GitWalker walk) throws IOException
    {
        if (Validates.isEmpty(parents))
            return;
        
        for (RevCommit p : parents)
        {
            p = walk.parseCommit(p);
            if (p.isHave())
                continue;
            
            p.setHave();
            p.setHaveParentRecursion(walk);
        }
    }
    
    /** 递归Have标志到所有的父节点，并把原haveList父节点删除 */
    public void setHaveParentRecursion(GitWalker walk, Set<RevCommit> haveList) throws IOException
    {
        if (Validates.isEmpty(parents))
            return;
        
        for (RevCommit p : parents)
        {
            p = walk.parseCommit(p);
            if (p.isHave())
            {
                haveList.remove(p);
                continue;
            }
            
            p.setHave();
            p.setHaveParentRecursion(walk);
        }
    }
    
    /***********************************************************************/
    //获取属性
    /***********************************************************************/

    public final RevTree getTree()
    {
        return tree;
    }
    
    public final List<RevCommit> getParents()
    {
        return parents;
    }
    
    public boolean hasParents()
    {
        return parents != null && !parents.isEmpty();
    }
    
    public final RevCommit getParent(int idx)
    {
        return parents.get(idx);
    }
    
    public final int getParentCount()
    {
        return parents==null?0:parents.size();
    }
    
    public final PersonIdent getAuthorIdent()
    {
        return author;
    }

    public final PersonIdent getCommitterIdent()
    {
        return committer;
    }
    
    public final int getCommitTime()
    {
        return commitTime;
    }
    
    /***********************************************************************/
    //作者&提交者&提交信息等属性
    /***********************************************************************/
    
    /** 获取字符串时间 */
    public String getCommitTimeString()
    {
        return DateTimes.toDateTimeString(commitTime * 1000L);
    }
    
    /** 获取提交完整消息 */
    public final String getFullMessage()
    {
        int off = GitBytes.paragraph(buffer, 0);
        if (off == buffer.length)
            return "";

        //读取可能的字符集
        Charset charset = GitBytes.encoding(buffer);
        return new String(buffer, off+1, buffer.length-off, charset);
    }

    /** 获取提交简短消息（第一段落），并去除换行符 */
    public final String getShortMessage()
    {
        int off = GitBytes.paragraph(buffer, 0);
        if (off == buffer.length)
            return "";
        
        Charset charset = GitBytes.encoding(buffer);
        int paragraph = GitBytes.paragraph(buffer, off+1);
        String message = new String(buffer, off, paragraph-off, charset);
        if (hasLF(buffer, off, paragraph))
            message = message.replace('\n', ' ');
        
        return message;
    }

    /** 用于显示提交整个内容 */
    public String toContent()
    {
        return Bytes.BU.toString(buffer);
    }
    
    @Override
    public String toString()
    {
        final StringBuilder s = new StringBuilder();
        s.append(type(getType()));
        s.append(' ');
        s.append(getName());
        s.append(' ');
        s.append(commitTime);
        s.append(' ');
        appendFlags(s);
        return s.toString();
    }
}
